package org

import (
	"errors"
	"fmt"
	"strings"
	"encoding/json"
	"dhfshop/utils/helper"
	"github.com/astaxie/beego"
	"dhfshop/service/redisgo"
)
type AuthenticatedUser struct {
	PartnerId         int64             `json:"partner_id"`
	OrderVersion      string            `json:"order_version"`    //订购版本
	RoleId            int64             `json:"role_id"`
	Admin             bool              `json:"admin"`
    Activated         bool              `json:"activated"`        //1=激活,0=停用
	UserId            int64             `json:"user_id"`
	OpenId            string            `json:"open_id"`
	AllowMapResAction map[string]string `json:"allowmap_res_action"`
	AllowStoreId      []int64           `json:"allow_store_ids"` //店铺隔离字段
	AllowAppId        []string          `json:"allow_app_ids"`   //appId隔离字段
	PartByUser        bool              `json:"part_by_user"`   //是否需要按照user隔离   
}

// 删除缓存用户
func RemoveCachedUser(partnerId, userId int) (err error) {
	redisconn := redisgo.GetInstance()
	cacheKey := fmt.Sprintf("%d_%d", partnerId, userId)
	err = redisconn.Del(cacheKey)
	return
}

// 从缓存中读取单个用户数据
func GetAuthUserFromCache(partnerId, roleId, userId int64) (*AuthenticatedUser, error) {
	var authUser *AuthenticatedUser = new(AuthenticatedUser)
	authUser.AllowMapResAction = make(map[string]string)
	//authUser.AllowStoreId = []int{}
	//authUser.AllowAppId = []string{}
	authUser.AllowStoreId = make([]int64, 0, 6)    //需要初始化为0个
	authUser.AllowAppId = make([]string, 0, 6)     
	authUser.PartByUser = false 
	cacheKey := fmt.Sprintf("%s_%d_%d","permission_",roleId,userId)
	redisconn := redisgo.GetInstance()
	if cacheValue, err := redisconn.GetString(cacheKey); err == nil && len(cacheValue) > 20  {
	    //beego.Debug("cache auth user", cacheValue)
		if err = json.Unmarshal([]byte(cacheValue), authUser); err == nil {
			return authUser, nil
		}
	}
	if authUser.PartnerId == 0 {
		if role, err := GetPartnerIdByRoleId(roleId); err == nil {
			authUser.PartnerId = partnerId
			if partner, err := GetPartnerById(partnerId); err == nil {
			    authUser.OrderVersion = partner.OrderVersion
			}
			authUser.RoleId = roleId
			authUser.Admin = role.IsSuperAdmin
			authUser.UserId = userId
			if user, err := GetUserByUserId(userId); err == nil {
			    authUser.Activated = user.Activated
				authUser.OpenId = user.OpenID
			}
			if permissions, err := GetPermissionsByRoleId(roleId); err == nil {
				for _, permission := range permissions {
					authUser.AllowMapResAction[permission.Identity] = permission.Action
				}
			}
			beego.Debug("roleId,userId,role.DataRange:",roleId,userId,role.DataRange)
			if len(role.DataRange) > 5 {
				//beego.Debug("role.DataRange: ", role.DataRange)
				authUser.AllowStoreId, authUser.AllowAppId, authUser.PartByUser, err = helper.JsonToDataRangeStr(role.DataRange,userId)
				if err != nil {
					beego.Debug("err: ", err.Error())
				}
	        }
		}
		if userJSON, err := json.Marshal(authUser); err == nil {
		    //beego.Debug("userJSON", string(userJSON))
			if _, err = redisconn.Set(cacheKey, string(userJSON), 3*3600); err != nil {  //3个小时过期,解决子账号权限过期的问题
			    beego.Debug("SETEX", err.Error())
			}
	    }
	}
	return authUser, nil
}

// 验证权限
func VerifyRolePermit(authUser *AuthenticatedUser,identity,action string) (string,error) {
	// 用户订购版本验证
	/*
	versionStr, ok := MapResourceVersion[identity]
	if !ok {
	   return "", errors.New("ORDER_VERSION_IS_ERROR")     
	}
	if ok := strings.Contains(versionStr, authUser.OrderVersion); !ok {
		return "", errors.New("ORDER_VERSION_IS_ERROR")
	}
	*/
	/*
	if !authUser.Activated {
	    return "", errors.New("user is not activated, please login agin")
	}
	*/
	/*
	beego.Debug("identity:", identity, "action:", action)
	if body, err := json.Marshal(authUser.AllowMapResAction); err == nil {
	    beego.Debug("AllowMapResAction:", string(body))
	}
	*/
	// 针对管理员,不做权限判断
    if authUser.Admin {
	    return "", nil
	}
	actionStr, ok := authUser.AllowMapResAction[identity]
	if !ok {
	   return "", errors.New("auth is not allow")     
	}
	authActionArr := strings.Split(actionStr, ",")	
	if _, err := helper.Contains(action, authActionArr); err != nil {
	   return "", errors.New("auth is not allow")
	}
    return "", nil	
}
